ci: add conventional commit and PR base checks#346
Merged
declan-scale merged 6 commits intomainfrom May 7, 2026
Merged
Conversation
Adds .github/workflows/lint-pr.yaml with two checks: 1. Conventional Commits: validates the PR title using amannn/action-semantic-pull-request (matches the pattern used in scale-agentex and agentex). Bypassable via the skip-conventional-commit-check label for automation that needs it. 2. PR base validation: fails on PRs targeting main, with exemptions for known automation accounts (stainless-app, release-please, github-actions, dependabot) and an opt-out via the target-main label. Encourages developer PRs to target next, where Stainless codegen and release-please integrate, while keeping main accessible for hotfixes.
The Stainless TS/Python repos restrict GitHub Actions to an allowlist that doesn't include amannn/action-semantic-pull-request. Using a pure-shell regex check keeps the workflow self-contained and removes the third-party dependency, which also reduces supply-chain risk.
In POSIX shell case patterns, [bot] is a glob character class that matches a single character (b/o/t), not the literal string '[bot]'. This meant release-please[bot], dependabot[bot], and the other bot exemptions never matched and those PRs would have been failed by validate-pr-base. Escape the brackets so the patterns match the actual GitHub App login strings. Caught by Greptile review.
…p label, document workflow Workflow changes: - validate-pr-base now posts (or updates) an explanatory PR comment when it fails, telling the contributor exactly how to resolve: either re-target the PR to `next` or add the `target-main` label. The comment is removed automatically when the check passes (re-target, label, or bot exemption). - validate-pr-title no longer honors the `skip-conventional-commit-check` label. Conventional Commits is enforced unconditionally so the release-please changelog stays consistent. Docs: - CONTRIBUTING.md gains (or updates) a "Contribution workflow" section covering the branch model and conventional commits, with the new CI enforcement notes and the `target-main` label escape hatch. - CLAUDE.md gains a short "Contribution workflow" section pointing to the same guidance for Claude Code sessions.
Contributor
Author
|
@greptile |
danielmillerp
approved these changes
May 7, 2026
…tion
GitHub Actions only processes workflow commands (::error, ::warning,
etc.) when they appear on stdout. The previous code wrote the ::error
line inside a {...} >&2 block, sending it to stderr — the job still
exited 1, but the red annotation linking back to the failing PR title
never appeared in the Actions UI. Move the ::error to stdout and keep
the long-form details on stderr.
Caught by Greptile review on the sgp-typescript PR; applied to all 4
repos for consistency since the same pattern existed in each.
…te lookup
Three fixes from review feedback, all in lint-pr.yaml:
1. Exempt automation accounts from validate-pr-title. Bots like dependabot
create PRs with non-Conventional-Commits titles by default
("Bump foo from 1.0 to 1.1"), and we don't want them blocked. The
exemption list mirrors validate-pr-base for consistency.
2. Make gh-CLI write failures non-fatal in validate-pr-base. Previously,
if `gh pr comment` or `gh api -X PATCH` failed (fork PR token without
upstream write scope, transient API error, rate limit), `set -e`
would abort the script and the ::error annotation + exit 1 never
ran. Now each write is guarded so the failure annotation always
reaches the contributor, and a ::warning explains when the comment
itself couldn't be written.
3. Use --paginate when looking up the marker comment. The default page
size is 30, so on busy PRs the marker could be missed and a duplicate
"PR should target next" comment posted on every workflow re-run.
Verified locally with a 28-case bash harness covering all branches:
valid/invalid title formats, bot-account variants (including
stainless-appx near-misses that should NOT be exempted), no-comment vs
existing-comment paths for the base check, and all gh-call failure
modes — every case behaves as expected.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds CI enforcement and contributor docs for two project conventions across the Stainless SDK repos:
next(notmain). Thenext → mainflow is what release-please and Stainless already use, so this aligns developer workflow with how releases are actually cut. PRs targetingmainfail the check and the workflow posts a PR comment with resolution steps; the comment is auto-deleted when the check passes (re-target, label, or bot exemption).What's in this PR
.github/workflows/lint-pr.yamlvalidate-pr-title— pure-shell regex against the project's release-please type list (feat,fix,docs,style,refactor,test,chore,ci,build,perf,revert).validate-pr-base— fails on PRs targetingmain, with exemptions for automation accounts (stainless-app,release-please[bot],github-actions[bot],dependabot[bot]) and a per-PRtarget-mainlabel escape hatch. Posts (or updates) an explanatory PR comment on failure and removes it once resolved.CONTRIBUTING.md— adds (or tightens) a "Contribution workflow" section covering the branch model and conventional-commits requirement, with notes on the new CI checks and thetarget-mainescape hatch.CLAUDE.md— adds a short "Contribution workflow" section so Claude Code sessions follow the same convention.Behavior
validate-pr-titlevalidate-pr-basenextwith valid titlenextwith invalid titlemainfrom human, no labelmainwithtarget-mainlabelmainfromrelease-please[bot]etc.main→nextTest plan
ci: ...).next.mainfailed the check and posted the explanatory comment; re-targeting tonextpassed the check and removed the comment.mainwithout friction.🤖 Generated with Claude Code
Greptile Summary
This PR adds two new GitHub Actions CI checks:
validate-pr-title(pure-shell Conventional Commits regex enforcement) andvalidate-pr-base(blocks PRs targetingmainfrom non-automation accounts, with a self-updating PR comment andtarget-mainlabel escape hatch). Documentation inCONTRIBUTING.mdandCLAUDE.mdis also updated to describe the new workflow conventions.Confidence Score: 4/5
Safe to merge with the understanding that Dependabot PRs may fail the title check if this is set as a required status check.
One P1 found: validate-pr-title lacks the bot exemptions present in validate-pr-base, and no dependabot.yml configures CC-format titles, meaning Dependabot dependency-update PRs will fail the title check. Score capped at 4 by the P1 ceiling.
.github/workflows/lint-pr.yaml — the validate-pr-title job needs bot exemptions mirroring those in validate-pr-base, or a dependabot.yml that configures CC-style commit prefixes.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[PR Event opened/edited/sync/label] --> B[validate-pr-title] A --> C[validate-pr-base] B --> B1{Title matches CC regex?} B1 -->|Yes| B2[✅ Pass] B1 -->|No| B3[❌ Fail ::error annotation] C --> C1{base == main?} C1 -->|No| C2[Delete marker comment ✅ Pass] C1 -->|Yes| C3{Bot author? stainless-app / release-please github-actions / dependabot} C3 -->|Yes| C4[Delete marker comment ✅ Pass] C3 -->|No| C5{Has target-main label?} C5 -->|Yes| C6[Delete marker comment ✅ Pass] C5 -->|No| C7[Post/update PR comment ❌ Fail]Prompt To Fix All With AI
Reviews (5): Last reviewed commit: "fix(ci): emit ::error to stdout so GitHu..." | Re-trigger Greptile